//////////////////////////////////////////////////////////////////////////
// CXnCan类实现Can的物理管理
// 实现Can通讯 
//                                       
// 1,XNWIN   USB转Can卡(周立功)           
// 2,XNLINUX socket can 依赖 libsocketcan.so
//
//  CGL 2016-09-24   创建
//  

#ifndef XN_CAN_H
#define XN_CAN_H

#ifdef XNWIN
#include <windows.h>
#include "win/ControlCAN.h"
#elif XNLINUX

#ifndef PF_CAN
#define PF_CAN 29
#endif

#ifndef AF_CAN
#define AF_CAN PF_CAN
#endif
#include <net/if.h>
#include "linux/libsocketcan.h"
#include <linux/can.h>
#include <linux/can/raw.h>
#endif

typedef struct _SCanIDBC
{
	unsigned int SA : 8;    // 源地址           扩展帧
	unsigned int DA : 8;    // 目标地址
	unsigned int PF : 8;    // 命令代码   8位
	unsigned int DP : 1;    // 固定为0
	unsigned int R :  1;    // 固定为0
	unsigned int Prio : 3;  // 优先级
}SCanIDBC;

//#ifdef XNWIN
//#pragma pack(push)      // 保存对齐状态
//#pragma pack(1)         // 设定为1字节对齐
//#define LINUX_PACK_1_BYTE  
//#elif XNLINUX
//#define LINUX_PACK_1_BYTE   __attribute__((packed))
//#endif

typedef struct _SCanMutiFrame 
{ 
	unsigned int can_id;   /* 32 bit CAN_ID + EFF/RTR/ERR flags */
	unsigned char can_dlc; /* 数据长度: 0 .. 8 */
	unsigned char data[8]; // Data
}SCanMutiFrame; // sizeof(SCanMutiFrame) = 16 与Linux struct can_frame 相同

//#ifdef XNWIN
//#pragma pack(pop)                  // 恢复对齐状态
//#endif

class CXnCan
{
public:
	CXnCan();
	~CXnCan();

public:
	 /*
	 pDeviceName := /dev/canX (unix) | CAN1 CAN2 (Windows) 
	 iSpeed      := 5K 10K 20K 50K 100K 125K 250K 500K 800K 1000K  
	 */
	 int openDevice(const char *pDeviceName, int iSpeed = 250 * 1000);
	 int closeDevice();    

	 int readFrame(unsigned int& uiCanId, unsigned char* pBuf, int iTimeout = -1);
	 int readMultiFrame(unsigned char* pBuf, int iFrameNum, int iTimeout = -1);	
	 int writeFrame(unsigned int uiCanId, unsigned char* pBuf, unsigned char uaLen);

private:
#if XNWIN
	void printLastErr();
#elif XNLINUX
	int select(int iTimeout = 500); // 设置超时时间  返回0 超时，其他未超时
#endif	

private:
	bool m_bOpenOK;       // 成功打开	

#ifdef XNWIN
	bool m_bInitDllOK;    // 打开dll失败
	int m_iDevtype;       // 设备类型
	DWORD m_dwDevind;     // 设备索引号

	HINSTANCE m_hDllInst; // Dll句柄
	VCI_CAN_OBJ canObj[100]; // 读100帧缓存

	pVCI_OpenDevice m_pVCI_OpenDevice;
	pVCI_InitCAN m_pVCI_InitCAN;
	pVCI_CloseDevice m_pVCI_CloseDevice;
	pVCI_StartCAN m_pVCI_StartCAN;
	pVCI_Receive m_pVCI_Receive;
	pVCI_Transmit m_pVCI_Transmit;	
	pVCI_ReadErrInfo m_pVCI_ReadErrInfo;
	pVCI_ClearBuffer m_pVCI_ClearBuffer;
#elif XNLINUX
	char m_aCanName[64];
	int m_fdSocketCan;
#endif
};

#endif // XN_CAN_H
